"""
用户、角色、权限分配
"""
import logging

from django.db.models import Q
from django.conf import settings
from django.utils.module_loading import import_string

from oracle.base import baseview
from oracle.models import ORole, OMenu, OPermission

logger = logging.getLogger(__name__)


def distribute(request):
    """
    权限分配
    :param request:
    :return:
    """
    data = {
        "operation": "list",
    }
    status = "success"
    template = "oracle/distribute_permissions.html"

    # 所有用户列表
    user_info = import_string(settings.SERVICE_USER_MODEL_CLASS)
    all_users = user_info.objects.filter(status=0).values_list(user_info.show_field(), "key")
    # 所有角色列表
    all_roles = ORole.objects.filter(status=0).values_list("title", "key")

    # 用户与角色数据
    data["all_users"] = [{"name": user[0], "key": user[1]} for user in all_users]
    data["all_roles"] = [{"name": role[0], "key": role[1]} for role in all_roles]

    baseview.get_context_data(request, logger, data)
    return baseview.render_handler(request, status, template=template, data=data)


def generate_menu_ztree(menu_tree, key=None, level=0):
    """
    生成完整的菜单树
    :param menu_tree: 菜单树列表 菜单树格式为 [{"key": xx, "parent": xx, "isParent": True, "name":yy, "open": True, }, {...}, 。。。。]
    :param key: 父级菜单节点，根据key查找子节点
    :param level: 查找子节点层级，用来确定是否进行展开设置
    :return:
    """
    # 菜单树为空,生成虚拟根节点
    if not menu_tree:
        menu_tree.append({"key": "root", "parent": None, "isParent": True, "name": "菜单列表", "open": True, })

    if key:
        # 如果存在key 查找以key为父节点或者关联权限的菜单
        # 但是需要确定key为正常key， 如果key为_self结尾说明是人为构造的key，需要解码
        if key.endswith("_self"):
            key = key.replace("_self", "")
        menu_tree_obj = OMenu.objects.filter(Q(parent__key=key, status=0) | Q(menu_inner__key=key, status=0))
    else:
        # 如果不存在key 查找顶级菜单
        menu_tree_obj = OMenu.objects.filter(parent__isnull=True, menu_inner__isnull=True, status=0)

    # 选取需要获得的字段
    menu_tree_obj = menu_tree_obj.values('key', 'menu_inner__key', 'title', 'parent__key', 'link_to_permission__key')

    # 循环获得的对象,格式化数据
    for item in menu_tree_obj:
        # 定义key值
        node = {"key": item["key"], "permission": item["link_to_permission__key"]}
        # 如果有 menu_inner__key 说明是一个内部关联菜单
        if item["menu_inner__key"]:
            # 父节点是内部关联菜单， 为了适应ztree特性，单独组合key值
            node["parent"] = f'{item["menu_inner__key"]}_self'
            # 父节点，不存在展开情况，不主动设置open选项
            node["isParent"] = False
            # name指明内部关联
            node["name"] = f"{item['title']}(inner)"
        else:
            # 只要不是内部关联菜单就显示为父节点
            node['isParent'] = True
            node['name'] = item['title']
            # 根据是否有权限区分是最终节点还是只是归档节点
            # 叶子节点添加自身，为了正常使用ztree
            if item['link_to_permission__key']:
                menu_tree.append({
                    "key": node["key"],
                    "permission": node["permission"],
                    "parent": f"{node['key']}_self",
                    "isParent": False,
                    "name": "self(node)"
                })
                node["key"] = f"{node['key']}_self"
                node["permission"] = None
            # 否则如果有 parent__key 说明是一个普通下层菜单
            if item["parent__key"]:
                # 父节点是上层菜单
                node["parent"] = item["parent__key"]
                node['open'] = True if level < 2 else False
            # 没有父节点,说明是顶级节点, 和普通菜单节点处理大致相同
            else:
                # 顶级节点设置父节点为root
                node["parent"] = "root"
                node['open'] = True
        menu_tree.append(node)
        if node.get('isParent'):
            generate_menu_ztree(menu_tree, node["key"], level + 1)


def generate_menu_tree(menu_tree, key=None, open_type="current"):
    """
    生成完整的菜单树
    :param menu_tree: 菜单树列表
    :type menu_tree: {"xx_key": {"parent": xx, "name":yy, "children": [], "inner_children": [], "permission": ""}, , 。。。。}
    :param key: 父级菜单节点，根据key查找子节点
    :param open_type: 打开类型
                current 默认，只打开当前节点
                all_map 打开所有的节点
    :return:
    """
    if key:
        # 如果存在key 查找以key为父节点或者关联权限的菜单
        # 但是需要确定key为正常key， 如果key为_self结尾说明是人为构造的key，需要解码
        if key.endswith("_self"):
            key = key.replace("_self", "")
        menu_tree_obj = OMenu.objects.filter(Q(parent__key=key, status=0) | Q(menu_inner__key=key, status=0))
    else:
        # 如果不存在key 查找顶级菜单
        menu_tree_obj = OMenu.objects.filter(parent__isnull=True, menu_inner__isnull=True, status=0)
        key = "root"

    # 选取需要获得的字段
    menu_tree_obj = menu_tree_obj.values('key', 'menu_inner__key', 'title', 'parent__key', 'link_to_permission__key')

    # 循环获得的对象,格式化数据
    for item in menu_tree_obj:
        # 是否扫描子节点标志
        scan = None

        node = {"parent": key, "children": [], "inner_children": [], "permission": item["link_to_permission__key"]}
        # 如果有 menu_inner__key 说明是一个内部关联菜单
        if item["menu_inner__key"]:
            # 父节点的内部子节点列表添加本节点
            menu_tree[key]["inner_children"].append(item["key"])
            # name指明内部关联
            node["name"] = f"{item['title']}(inner)"
        elif item["parent__key"]:
            menu_tree[key]["children"].append(item["key"])
            # name指明内部关联
            node["name"] = item['title']
            scan = True
        else:
            # 都没有说明为顶级节点
            node["parent"] = "root"
            node["name"] = item['title']
            menu_tree[key]["children"].append(item["key"])
            scan = True
        # menu_tree 存储查询到的节点
        menu_tree[item["key"]] = node
        # 判断全部扫描菜单树标志
        if open_type == "all_map" and scan:
            # 递归扫描节点
            generate_menu_tree(menu_tree, item["key"], open_type)


def distribute_info(request):
    """
    权限分配信息
    :param request:
    :return:
    """
    data = {
        "operation": "list",
    }
    # ajax接口，返回json数据
    force_external_render = "external"
    # 状态信息
    status = "success"

    if request.method == "GET":
        info_type = request.GET.get('type')
        # 获取权限分配的菜单信息(专为ztree生成格式)
        if info_type == "menu_ztree":
            # 获取key值
            key = request.GET.get('key')
            data["menu_tree"] = list()
            generate_menu_ztree(data["menu_tree"], key, 0)
        elif info_type == "menu":
            # 获取key值
            key = request.GET.get('key')
            # 打开类型
            # current 默认，只打开当前节点
            # all_map 打开所有的节点
            open_type = request.GET.get("open")
            data["menu_tree"] = dict()
            base_menu_node = {"parent": "", "name": "", "children": [], "inner_children": [], "permission": ""}
            if key:
                data["menu_tree"] = {key: base_menu_node}
            else:
                base_menu_node["name"] = "菜单列表"
                data["menu_tree"] = {"root": base_menu_node}
            generate_menu_tree(data["menu_tree"], key, open_type)
        # 获取用户包含的角色
        elif info_type == "roles":
            role_list = list()
            user_key = request.GET.get('key')
            user_info = import_string(settings.SERVICE_USER_MODEL_CLASS)
            user_obj = user_info.objects.filter(key=user_key, status=0).first()
            if user_obj:
                role_obj = user_obj.roles.filter(status=0)
                for item in role_obj:
                    role_list.append({"key": item.key, "name": item.title})
            data["role_list"] = role_list
        # 获取用户包含的权限
        elif info_type == "permissions":
            menu_dict = dict()
            role_list = request.GET.getlist('role_list')
            for role in role_list:
                menu_obj = OMenu.objects.filter(link_to_permission__orole__key=role, status=0)
                menu_dict[role] = list()
                for menu in menu_obj:
                    menu_dict[role].append({"key": menu.key})
            data["menu"] = menu_dict
        else:
            status = "distribute_info_type_error"
    elif request.method == "POST":
        info_type = request.POST.get('type')
        # 设置用户的角色信息
        if info_type == "set_roles":
            role_list = request.POST.getlist('role_list')
            user_key = request.POST.get('user_key')
            if user_key:
                user_info = import_string(settings.SERVICE_USER_MODEL_CLASS)
                user_obj = user_info.objects.filter(key=user_key, status=0).first()
                if user_obj:
                    # TODO 索引不存在，捕获异常处理
                    user_obj.roles.set(ORole.objects.filter(key__in=role_list, status=0))
                else:
                    status = "user_object_not_exist"
            else:
                status = "user_key_get_none"
        # 设置角色的权限信息
        elif info_type == "set_permission":
            permission_list = request.POST.getlist('permission_list')
            role_key = request.POST.get('role_key')
            if role_key:
                role_obj = ORole.objects.filter(key=role_key, status=0).first()
                if role_obj:
                    # TODO 索引不存在，捕获异常处理
                    role_obj.permissions.set(OPermission.objects.filter(key__in=permission_list, status=0))
                else:
                    status = "role_object_not_exist"
            else:
                status = "role_key_get_none"
        else:
            status = "distribute_info_type_error"
    # 非get或者post方法访问进行友好报错处理
    else:
        status = "method_not_allow"
    kwargs = {"render": force_external_render}
    baseview.get_context_data(request, logger, data, **kwargs)
    return baseview.render_handler(request, status, data=data, render=force_external_render)
